/*
 * 
 *  This file is part of Sourceprojects.org Lycia Copyright 2010 noctarius
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 * 
 */
package org.sourceprojects.xmlparser.internal;

import java.io.File;
import java.io.InputStream;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.log4j.Logger;
import org.sourceprojects.lycia.LyciaParser;
import org.sourceprojects.lycia.exceptions.LyciaParsingException;
import org.sourceprojects.xmlparser.ParserContext;
import org.sourceprojects.xmlparser.ProgressListener;
import org.sourceprojects.xmlparser.ResourceResolver;
import org.sourceprojects.xmlparser.TagDefinitionParser;
import org.sourceprojects.xmlparser.XmlParser;
import org.sourceprojects.xmlparser.exceptions.XmlParserParsingException;
import org.w3c.dom.Document;
import org.xml.sax.ErrorHandler;

/**
 * 
 * @author noctarius
 * @since 0.0.1
 * 
 * @param <B>
 */
public class XmlParserAdapter<B> implements XmlParser<B> {
	private static final Logger LOGGER = Logger
			.getLogger(XmlParserAdapter.class.getName());

	private final LyciaParser<B> lyciaParser;
	private final List<ProgressListenerAdapter> listenerAdapters = new ArrayList<ProgressListenerAdapter>();
	private final List<TagDefinitionParserAdapter<B>> parserAdapters = new ArrayList<TagDefinitionParserAdapter<B>>();

	public XmlParserAdapter(final LyciaParser<B> lyciaParser) {
		this.lyciaParser = lyciaParser;
	}

	@Override
	public void addProgressListener(final ProgressListener listener) {
		final ProgressListenerAdapter adapter = new ProgressListenerAdapter(
				listener);
		lyciaParser.addProgressListener(adapter);
		listenerAdapters.add(adapter);
	}

	@Override
	public void addTagDefinitionParser(
			final TagDefinitionParser<B> definitionParser) {
		final TagDefinitionParserAdapter<B> adapter = new TagDefinitionParserAdapter<B>(
				definitionParser);
		lyciaParser.getConfigurator().addTagDefinitionParser(adapter);
		parserAdapters.add(adapter);
	}

	@Override
	public void addTagDefinitionParsers(
			final TagDefinitionParser<B>[] definitionParsers) {

		for (final TagDefinitionParser<B> definitionParser : definitionParsers) {
			addTagDefinitionParser(definitionParser);
		}
	}

	@Override
	public ErrorHandler getErrorHandler() {
		return lyciaParser.getErrorHandler();
	}

	@Override
	public ParserContext<B> getParserContext() {
		return (ParserContext<B>) lyciaParser.getParserContext();
	}

	@Override
	public ResourceResolver getResourceResolver() {
		final org.sourceprojects.lycia.ResourceResolver resolver = lyciaParser
				.getResourceResolver();

		if (resolver instanceof ResourceResolverAdapter) {
			return ((ResourceResolverAdapter) resolver).getWrappedResolver();
		}

		throw new RuntimeException(
				"Found ResourceResolver isn't of type org.sourceprojects.xmlparser.internal.ResourceResolverAdapter");
	}

	@Override
	public boolean isValidatingSchema() {
		return lyciaParser.isValidatingSchema();
	}

	@Override
	public void parse(final Reader reader) throws XmlParserParsingException {
		try {
			lyciaParser.parse(reader);
		} catch (final LyciaParsingException e) {
			throw new XmlParserParsingException(e);
		}
	}

	@Override
	public void parse(final String xml) throws XmlParserParsingException {
		try {
			lyciaParser.parse(xml);
		} catch (final LyciaParsingException e) {
			throw new XmlParserParsingException(e);
		}
	}

	@Override
	public void parse(final InputStream inputStream)
			throws XmlParserParsingException {
		try {
			lyciaParser.parse(inputStream);
		} catch (final LyciaParsingException e) {
			throw new XmlParserParsingException(e);
		}
	}

	@Override
	public void parse(final File file) throws XmlParserParsingException {
		try {
			lyciaParser.parse(file);
		} catch (final LyciaParsingException e) {
			throw new XmlParserParsingException(e);
		}
	}

	@Override
	public void removeProgressListener(final ProgressListener listener) {
		final Iterator<ProgressListenerAdapter> iterator = listenerAdapters
				.iterator();

		while (iterator.hasNext()) {
			final ProgressListenerAdapter adapter = iterator.next();

			if (adapter.getWrappedListener() == listener) {
				lyciaParser.removeProgressListener(adapter);
				iterator.remove();
			}
		}
	}

	@Override
	public void removeTagDefinitionParser(
			final TagDefinitionParser<B> definitionParser) {

		final Iterator<TagDefinitionParserAdapter<B>> iterator = parserAdapters
				.iterator();

		while (iterator.hasNext()) {
			final TagDefinitionParserAdapter<B> adapter = iterator.next();

			if (adapter.getWrappedTagDefinitionParser() == definitionParser) {
				lyciaParser.removeTagDefinitionParser(adapter);
				iterator.remove();
			}
		}
	}

	@Override
	public void removeTagDefinitionParsers(
			final TagDefinitionParser<B>[] definitionParsers) {

		for (final TagDefinitionParser<B> definitionParser : definitionParsers) {
			removeTagDefinitionParser(definitionParser);
		}
	}

	@Override
	public void setErrorHandler(final ErrorHandler errorHandler) {
		lyciaParser.setErrorHandler(errorHandler);
	}

	@Override
	public void setParserContext(final ParserContext<B> parserContext) {
		lyciaParser.setParserContext(parserContext);
	}

	@Override
	public void setResourceResolver(final ResourceResolver resourceResolver) {
		lyciaParser.setResourceResolver(new ResourceResolverAdapter(
				resourceResolver));
	}

	@Override
	public void setValidatingSchema(final boolean validatingSchema) {
		lyciaParser.setValidatingSchema(validatingSchema);
	}

	@Override
	public Document transform(final Reader reader)
			throws XmlParserParsingException {
		try {
			return lyciaParser.transform(reader);
		} catch (final LyciaParsingException e) {
			throw new XmlParserParsingException(e);
		}
	}

	@Override
	public Document transform(final String xml)
			throws XmlParserParsingException {
		try {
			return lyciaParser.transform(xml);
		} catch (final LyciaParsingException e) {
			throw new XmlParserParsingException(e);
		}
	}

	@Override
	public Document transform(final InputStream inputStream)
			throws XmlParserParsingException {

		try {
			return lyciaParser.transform(inputStream);
		} catch (final LyciaParsingException e) {
			throw new XmlParserParsingException(e);
		}
	}

	@Override
	public Document transform(final File file) throws XmlParserParsingException {
		try {
			return lyciaParser.transform(file);
		} catch (final LyciaParsingException e) {
			throw new XmlParserParsingException(e);
		}
	}

}
